/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package kimo.bl;

import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import kimo.persistence.controllers.DaokJpaController;

import kimo.persistence.controllers.MunicipalityJpaController;
import kimo.persistence.controllers.PcheckJpaController;
import kimo.persistence.controllers.PrefectureJpaController;
import kimo.persistence.controllers.ProducerJpaController;
import kimo.persistence.controllers.ProductCategoryJpaController;
import kimo.persistence.controllers.ProductJpaController;
import kimo.persistence.controllers.ProductionJpaController;
import kimo.persistence.controllers.RawProductJpaController;
import kimo.persistence.controllers.RawProductTypeJpaController;
import kimo.persistence.controllers.RegionJpaController;
import kimo.persistence.controllers.UserJpaController;
import kimo.persistence.controllers.exceptions.NonexistentEntityException;
import kimo.persistence.entities.Daok;

import kimo.persistence.entities.Municipality;
import kimo.persistence.entities.Pcheck;
import kimo.persistence.entities.Prefecture;
import kimo.persistence.entities.Producer;
import kimo.persistence.entities.Product;
import kimo.persistence.entities.ProductCategory;
import kimo.persistence.entities.ProductType;

import kimo.persistence.entities.Production;
import kimo.persistence.entities.RawProduct;
import kimo.persistence.entities.RawProductType;
import kimo.persistence.entities.Region;
import kimo.persistence.entities.User;
import org.zkoss.zk.ui.Session;
import org.zkoss.zk.ui.Sessions;

/**
 *
 * @author a381u296
 */
public class KimoDAO {

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("KimoPU");
    ProducerJpaController pjc = new ProducerJpaController(emf);
    UserJpaController ujc = new UserJpaController(emf);
    RegionJpaController rjc = new RegionJpaController(emf);
    PrefectureJpaController prefectureJpaController
            = new PrefectureJpaController(emf);
    MunicipalityJpaController mjc = new MunicipalityJpaController(emf);
    RawProductTypeJpaController rptjc = new RawProductTypeJpaController(emf);
    RawProductJpaController rpjc = new RawProductJpaController(emf);
    ProductCategoryJpaController pcjc = new ProductCategoryJpaController(emf);
    ProductionJpaController productionJpaController
            = new ProductionJpaController(emf);
    ProductJpaController productJpaController = new ProductJpaController(emf);
    PcheckJpaController pcheckJpaController = new PcheckJpaController(emf);
    DaokJpaController daokJpaController = new DaokJpaController(emf);

    private Producer producer;
    private List<Producer> producers;

    private User user;
    private final boolean admin;

    // για καθε query θα φτιαξω αλλο ενα για admin χρηστη οπου 
    // ΔΕΝ θα εχει το " AND p.producerDaokCd = :userDaokCd"
    // ή ακομα πιο εξυπνα ΑΝ ο χρηστης ΔΕΝ ειναι admin θα κοτσαρω στο string to
    private final String admQryProducerLikeSurname
            = "SELECT p FROM Producer p WHERE p.producerSurname LIKE :producerSurname";

    private final String qryProducerById = "SELECT p FROM Producer p WHERE p.producerId = :producerId"
            + " AND p.producerDaokCd = :userDaokCd";

    private final String qryProducerLikeSurname = "SELECT p FROM Producer p WHERE p.producerSurname LIKE :producerSurname"
            + " AND p.producerDaokCd = :userDaokCd";

    private final String qryFindPendingProducers = "SELECT p FROM Producer p"
            + " WHERE p.producerSubmittedAppliation = true"
            + " AND p.producerDaokCd = :userDaokCd "
            + " AND p.producerConfirmed = false";

    private final String admQryFindPendingProducers = "SELECT p FROM Producer p"
            + " WHERE p.producerSubmittedAppliation = true "
            + " AND p.producerConfirmed = false";

    private final String qryFindDaokOrdered = "SELECT d FROM Daok d ORDER BY d.daokName";

    public KimoDAO() {
        // get the current user
        Session session = Sessions.getCurrent();
        user = (User) session.getAttribute("user");

        if (user != null) {
            admin = user.getUserAdmin();
        } else {
            admin = false;
        }

        // και τον κανω admin για τις δοκιμές μου
        // μαλλον αυτο εινα αχρηστο αλλα οκ :D
        producer = null;

    }

    public Producer findById(Integer id) {

        //emf.getCache().evictAll();
        if (!admin) {
            producer = (Producer) pjc.getEntityManager().createQuery(qryProducerById)
                    .setParameter("producerId", id)
                    .setParameter("userDaokCd", user.getUserDaokCd())
                    .getSingleResult();
        } else {

            producer = pjc.findProducer(id);
        }
        return producer;
    }

    public Producer findByAfm(String afm) {
        try {
            producer = (Producer) pjc.getEntityManager()
                    .createNamedQuery("Producer.findByProducerAfm")
                    .setParameter("producerAfm", afm)
                    .getSingleResult();

        } catch (NoResultException nre) {
            producer = null;
        }

        return producer;
    }

    public List<Producer> findBySurname(String surname) {

        // emf.getCache().evictAll();
        // get the current user , προς το παρον παιρνω τον 1 καρφωτα
        if (!admin) {
            producers = pjc.getEntityManager()
                    .createQuery(qryProducerLikeSurname)
                    .setParameter("producerSurname", surname + "%")
                    .setParameter("userDaokCd", user.getUserDaokCd())
                    .getResultList();
        } else {
            producers = pjc.getEntityManager()
                    .createQuery(admQryProducerLikeSurname)
                    .setParameter("producerSurname", surname + "%")
                    .getResultList();
        }
        return producers;
    }

    public Producer findById(String sid) {

        int id;

        try {
            id = Integer.parseInt(sid);
        } catch (NumberFormatException nfe) {
            return null;
        }

        if (!admin) {
            producer = (Producer) pjc.getEntityManager().createQuery(qryProducerById)
                    .setParameter("producerId", id)
                    .setParameter("userDaokCd", user.getUserDaokCd())
                    .getSingleResult();
        } else {
            producer = pjc.findProducer(id);
        }
        return producer;
    }

    /**
     *
     * @return
     */
    public List<Producer> findPending() {
        if (!admin) {
            producers = pjc.getEntityManager()
                    .createQuery(qryFindPendingProducers)
                    .setParameter("userDaokCd", user.getUserDaokCd())
                    .getResultList();
        } else {
            producers = pjc.getEntityManager()
                    .createQuery(admQryFindPendingProducers)
                    .getResultList();
        }
        return producers;
    }

    /**
     *
     * @param producer try to edit the producer
     * @return string 'ok' if succeeds
     * @throws NonexistentEntityException
     * @throws Exception
     */
    public String save(Producer producer) throws NonexistentEntityException, Exception {
        pjc.edit(producer);
        return "ok";

    }

    /**
     *
     * @return a list of all regions
     */
    List<Region> getAllRegions() {
        return rjc.findRegionEntities();
    }

    /**
     *
     * @return a List of producer Prefectures (ie region prefectures)
     */
    List<Prefecture> getProducerPrefectures() {
        Region region = producer
                .getProducerMunicipalityId()
                .getMunicipalityPrefectureId()
                .getPrefectureRegionId();

        return region.getPrefectureList();
    }

    /**
     *
     * @return a List of producer Prefectures (ie region prefectures)
     */
    List<Prefecture> getProducerRuralPrefectures() {
        Region region = producer
                .getProducerRuralMunicipalityId()
                .getMunicipalityPrefectureId()
                .getPrefectureRegionId();

        return region.getPrefectureList();
    }

    List<Municipality> getProducerMunicipalities() {
        Prefecture prefecture = producer
                .getProducerMunicipalityId()
                .getMunicipalityPrefectureId();
        return prefecture.getMunicipalityList();
    }

    List<Municipality> getProducerRuralMunicipalities() {
        Prefecture prefecture = producer
                .getProducerRuralMunicipalityId()
                .getMunicipalityPrefectureId();
        return prefecture.getMunicipalityList();
    }

    List<Production> getProducerProductions() {
        return producer.getProductionList();
    }

    List<RawProductType> getRawProductTypes() {
        return rptjc.findRawProductTypeEntities();
    }

    List<RawProduct> getRawProducts(RawProductType rawProductType) {
        return rawProductType.getRawProductList();
    }

    List<ProductCategory> getProductCategories() {
        return pcjc.findProductCategoryEntities();
    }

    List<ProductType> getProductTypes(ProductCategory productCategory) {
        return productCategory.getProductTypeList();
    }

    List<Product> getProduct(ProductType productType) {
        return productType.getProductList();
    }

    void saveNewProduction(Production productionItem) {
        productionItem.setProductionProducerId(producer);
        productionJpaController.create(productionItem);

    }

    void saveProduct(Product product) {

        productJpaController.create(product);

    }

    void editProduction(Production productionItem) throws Exception {
        productionJpaController.edit(productionItem);
    }

    void deleteProduction(Production productionItem) throws NonexistentEntityException {

        productionJpaController.destroy(productionItem.getProductionId());
    }

    List<Pcheck> getPchecks() {
        return producer.getPcheckList();
    }

    void saveNewPCheck(Pcheck pCheck) {
        pCheck.setCheckProducerId(producer);
        pCheck.setCheckUserId(user);

        pcheckJpaController.create(pCheck);
    }

    void editPCheck(Pcheck pCheck) throws Exception {
        pcheckJpaController.edit(pCheck);
    }

    void deletePcheck(Pcheck pCheck) throws NonexistentEntityException {
        pcheckJpaController.destroy(pCheck.getCheckId());
    }

    User getUser() {
        return user;
    }

    List<Daok> getDaoks() {

        return daokJpaController
                .getEntityManager()
                .createQuery(qryFindDaokOrdered)
                .getResultList();
    }

    String insertUser(User user) {

        List usernameList = ujc.getEntityManager()
                .createNamedQuery("User.findByUsername")
                .setParameter("username", user.getUsername())
                .getResultList();
        if (usernameList.isEmpty()) {
            List emailList = ujc.getEntityManager()
                    .createNamedQuery("User.findByUserEmail")
                    .setParameter("userEmail", user.getUserEmail())
                    .getResultList();
            if (emailList.isEmpty()) {
                ujc.create(user);
                return "ok";
            } else {

                return "email_exists";
            }
        } else {

            return "username_exists";
        }

    }

}
